﻿#include "YDecoder.h"
#include <QDebug>

extern"C"
{
#include "libavcodec/avcodec.h"
#include "libavutil/avutil.h"
#include "libavutil/opt.h"
}

/// <summary>
/// 发送解码
/// </summary>
/// <param name="pkt">未解码的包</param>
/// <returns></returns>
bool YDecoder::Send(const AVPacket* pkt)
{
	std::unique_lock<std::mutex> lock(m_mutex);
	if (!m_context)
	{
		qDebug() << "Send->编解码器上下文异常";
		return false;
	}
	/*int packet_ref_count = pkt->buf ? av_buffer_get_ref_count(pkt->buf) : 0;
	qDebug() << "AVPacket的引用计数=>" << packet_ref_count;*/
	auto re = avcodec_send_packet(m_context, pkt);
	if (re != 0)
	{
		PrintError(re, "avcodec_send_packet");
		return false;
	}
	return true;
}


/// <summary>
/// 获取解码
/// </summary>
/// <param name="frame">解码后的AVFrame</param>
/// <returns></returns>
bool YDecoder::Receive(AVFrame* frame)
{
	std::unique_lock<std::mutex> lock(m_mutex);
	if (!m_context)
	{
		qDebug() << "Receive->编解码器上下文异常";
		return false;
	}
	/*if (!frame || frame->width <= 0 || frame->height <= 0)
	{
		qDebug() << "传入的frame是空的";
		return false;
	}*/
	auto f = frame;
	if (m_context->hw_device_ctx) //硬件加速
	{
		f = av_frame_alloc();
	}
	auto re = avcodec_receive_frame(m_context, f);
	/*int frame_ref_count = frame->buf[0] ? av_buffer_get_ref_count(frame->buf[0]) : 0;
	qDebug() << "AVFrame的引用计数=>" << frame_ref_count;*/
	if (re == 0)
	{
		if (m_context->hw_device_ctx) //GPU解码
		{
			//显存转内存 GPU =》 CPU
			re = av_hwframe_transfer_data(frame, f, 0);
			av_frame_free(&f);
			if (re != 0)
			{
				PrintError(re, "av_hwframe_transfer_data");
				return false;
			}
		}
		return true;
	}
	/*else if (re == AVERROR(EAGAIN) || re == AVERROR_EOF)
	{
		qDebug() << "没有可输出的视频帧";
		PrintError(re, "avcodec_receive_frame");
		if (f)
		{
			av_frame_free(&f);
		}
		return false;
	}
	else {
		if (f)
		{
			av_frame_free(&f);
		}
		qDebug() << "解码视频帧失败";
		return false;


	}*/
	if (m_context->hw_device_ctx)
		av_frame_free(&f);
	return false;
}

bool YDecoder::InitHW(int type)
{
	std::unique_lock<std::mutex> lock(m_mutex);
	if (!m_context)return false;
	AVBufferRef* ctx = nullptr; //硬件加速上下文
	auto re = av_hwdevice_ctx_create(&ctx, (AVHWDeviceType)type, NULL, NULL, 0);
	if (re != 0)
	{
		PrintError(re, "av_hwdevice_ctx_create");
		return false;
	}
	m_context->hw_device_ctx = ctx;
	qDebug() << "硬件加速：" << type;
	return true;
}

/// <summary>
/// 获取缓冲中的数据
/// </summary>
/// <returns></returns>
std::vector<AVFrame*> YDecoder::End()
{
	std::vector<AVFrame*> res;
	std::unique_lock<std::mutex> lock(m_mutex);
	if (!m_context)return res;

	///取出缓存数据
	int ret = avcodec_send_packet(m_context, NULL);
	while (ret >= 0)
	{
		auto frame = av_frame_alloc();
		ret = avcodec_receive_frame(m_context, frame);
		if (ret < 0)
		{
			av_frame_free(&frame);
			break;
		}
		res.push_back(frame);
	}
	return res;
}

YDecoder::YDecoder()
{
}

YDecoder::~YDecoder()
{
}
